package org.dftproject.genesis.ui.figures;

import java.util.Iterator;

import org.eclipse.draw2d.ColorConstants;
import org.eclipse.draw2d.Cursors;
import org.eclipse.draw2d.Figure;
import org.eclipse.draw2d.FocusEvent;
import org.eclipse.draw2d.Graphics;
import org.eclipse.draw2d.MouseEvent;
import org.eclipse.draw2d.MouseListener;
import org.eclipse.draw2d.MouseMotionListener;
import org.eclipse.draw2d.geometry.Dimension;
import org.eclipse.draw2d.geometry.Insets;
import org.eclipse.draw2d.geometry.Rectangle;
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Color;

public class CloseButtonFigure extends Figure {
	
	public static final String HOVER_STATE = "hover";
	
	private final Color hoverTopTop = new Color(null, 0xFF, 0xAA, 0xAA);
	private final Color hoverTopBottom = new Color(null, 0xFF, 0, 0);
	private final Color hoverBottomTop = new Color(null, 0x99, 0, 0);
	private final Color hoverBottomBottom = new Color(null, 0xFF, 0, 0);
	
	private final Color selectedTopTop = new Color(null, 0xFF, 0xDD, 0xDD);
	private final Color selectedTopBottom = new Color(null, 0xFF, 0x22, 0x22);
	private final Color selectedBottomTop = new Color(null, 0xFF, 0, 0);
	private final Color selectedBottomBottom = new Color(null, 0xFF, 0x22, 0x22);
	
	private final Color normalTopTop = new Color(null, 0xDD, 0xDD, 0xDD);
	private final Color normalTopBottom = new Color(null, 0xBB, 0xBB, 0xBB);
	private final Color normalBottomTop = new Color(null, 0x99, 0x99, 0x99);
	private final Color normalBottomBottom = new Color(null, 0xBB, 0xBB, 0xBB);
	
	private boolean selected;
	private boolean hover;
	
	public CloseButtonFigure() {
		setCursor(Cursors.HAND);
		setRequestFocusEnabled(true);
		addListeners();
	}
	
	@Override
	public Dimension getPreferredSize(int wHint, int hHint) {
		Insets insets = getInsets();
		return new Dimension(16, 16).expand(insets.getWidth(), insets.getHeight());
	}

	protected void addListeners() {
		MouseTracker tracker = new MouseTracker();
		addMouseMotionListener(tracker);
		addMouseListener(tracker);
	}
	
	@Override
	public void handleFocusGained(FocusEvent event) {
		super.handleFocusGained(event);
		repaint();
	}

	@Override
	public void handleFocusLost(FocusEvent event) {
		super.handleFocusLost(event);
		repaint();
	}
	
	@Override
	public void paintFigure(Graphics graphics) {
		super.paintFigure(graphics);
		
		graphics.pushState();
		graphics.setAntialias(SWT.ON);
		
		Rectangle clientArea = getClientArea();
		clientArea = clientArea.getExpanded(7 - clientArea.width / 2, 7 - clientArea.height / 2);
		
		if (hover) {
			graphics.setForegroundColor(hoverTopTop);
			graphics.setBackgroundColor(hoverTopBottom);
			graphics.fillGradient(clientArea.getResized(0, -clientArea.height / 2), true);
	
			graphics.setForegroundColor(hoverBottomTop);
			graphics.setBackgroundColor(hoverBottomBottom);
			graphics.fillGradient(clientArea.getResized(0, -clientArea.height / 2).getTranslated(0, clientArea.height / 2), true);
			
			graphics.setForegroundColor(hoverBottomTop);
			graphics.drawRoundRectangle(clientArea.getExpanded(new Insets(1, 1, 0, 0)), 6, 6);
			
			clientArea = clientArea.getCropped(new Insets(4));
			
			graphics.setLineWidth(2);
			graphics.setForegroundColor(ColorConstants.white);
			graphics.drawLine(clientArea.getTopLeft(), clientArea.getBottomRight());
			graphics.drawLine(clientArea.getTopRight(), clientArea.getBottomLeft());
		} else if (selected || hasFocus()) {
			graphics.setForegroundColor(selectedTopTop);
			graphics.setBackgroundColor(selectedTopBottom);
			graphics.fillGradient(clientArea.getResized(0, -clientArea.height / 2), true);
	
			graphics.setForegroundColor(selectedBottomTop);
			graphics.setBackgroundColor(selectedBottomBottom);
			graphics.fillGradient(clientArea.getResized(0, -clientArea.height / 2).getTranslated(0, clientArea.height / 2), true);
			
			graphics.setForegroundColor(selectedBottomTop);
			graphics.drawRoundRectangle(clientArea.getExpanded(new Insets(1, 1, 0, 0)), 6, 6);
			
			clientArea = clientArea.getCropped(new Insets(4));
			
			graphics.setLineWidth(2);
			graphics.setForegroundColor(ColorConstants.white);
			graphics.drawLine(clientArea.getTopLeft(), clientArea.getBottomRight());
			graphics.drawLine(clientArea.getTopRight(), clientArea.getBottomLeft());
		} else {
			graphics.setForegroundColor(normalTopTop);
			graphics.setBackgroundColor(normalTopBottom);
			graphics.fillGradient(clientArea.getResized(0, -clientArea.height / 2), true);
	
			graphics.setForegroundColor(normalBottomTop);
			graphics.setBackgroundColor(normalBottomBottom);
			graphics.fillGradient(clientArea.getResized(0, -clientArea.height / 2).getTranslated(0, clientArea.height / 2), true);
			
			graphics.setForegroundColor(normalBottomTop);
			graphics.drawRoundRectangle(clientArea.getExpanded(new Insets(1, 1, 0, 0)), 6, 6);
			
			clientArea = clientArea.getCropped(new Insets(4));
			
			graphics.setLineWidth(2);
			graphics.setForegroundColor(ColorConstants.white);
			graphics.drawLine(clientArea.getTopLeft(), clientArea.getBottomRight());
			graphics.drawLine(clientArea.getTopRight(), clientArea.getBottomLeft());
		}
		
		graphics.popState();
	}

	public boolean isSelected() {
		return selected;
	}

	public void setSelected(boolean selected) {
		this.selected = selected;
	}

	public boolean isHover() {
		return hover;
	}

	public void setHover(boolean hover) {
		boolean oldHover = this.hover;
		this.hover = hover;
		firePropertyChange(HOVER_STATE, oldHover, hover);
	}
	
	public void addSelectionListener(ISelectionListener listener) {
		addListener(ISelectionListener.class, listener);
	}
	
	public void removeSelectionListener(ISelectionListener listener) {
		removeListener(ISelectionListener.class, listener);
	}

	protected void handleSelected() {
		Iterator<?> iter = getListeners(ISelectionListener.class);
		while (iter.hasNext())
			((ISelectionListener) iter.next()).selected();
	}

	protected class MouseTracker extends MouseMotionListener.Stub implements MouseListener {

		private boolean mouseDown;

		public void mousePressed(MouseEvent me) {
			if (me.button == 1) {
				requestFocus();
				me.consume();
	
				mouseDown = true;
			}
		}

		public void mouseReleased(MouseEvent me) {
			if (mouseDown && me.button == 1) {	
				if (getBounds().contains(me.getLocation()))
					handleSelected();
				
				mouseDown = false;
			}
		}

		public void mouseDoubleClicked(MouseEvent me) {
		}

		@Override
		public void mouseEntered(MouseEvent me) {
			setHover(true);
			repaint();
		}

		@Override
		public void mouseExited(MouseEvent me) {
			setHover(false);
			repaint();
		}

		@Override
		public void mouseDragged(MouseEvent me) {
			setHover(getBounds().contains(me.getLocation()));
			repaint();
		}

	}

}
